#include <Windows.h>
#include <tchar.h>
#include <Dbt.h>
#include <setupapi.h>
#include <iostream>
#include <atlstr.h> // CString
using namespace std;

#pragma comment (lib, "Kernel32.lib")
#pragma comment (lib, "User32.lib")

#define THRD_MESSAGE_EXIT WM_USER + 1
const _TCHAR CLASS_NAME[] = _T("USB Detection Class");

HWND hWnd;

typedef struct _USBINFO_
{
	char type[16];
	char VID[16];
	char PID[16];
	char ID[16];
}USBINFO, *PUSBINFO;

static const GUID GUID_DEVINTERFACE_LIST[] =
{
	// GUID_DEVINTERFACE_USB_DEVICE   USB设备
	{ 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } },
	// GUID_DEVINTERFACE_DISK
	{ 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } },
	// GUID_DEVINTERFACE_HID, 
	{ 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } },
	// GUID_NDIS_LAN_CLASS
	{ 0xad498944, 0x762f, 0x11d0, { 0x8d, 0xcb, 0x00, 0xc0, 0x4f, 0xc3, 0x35, 0x8c } }
	//,
	//// GUID_DEVINTERFACE_COMPORT
	//{ 0x86e0d1e0, 0x8089, 0x11d0, { 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73 } },
	//// GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR
	//{ 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } },
	//// GUID_DEVINTERFACE_PARALLEL
	//{ 0x97F76EF0, 0xF883, 0x11D0, { 0xAF, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x84, 0x5C } },
	//// GUID_DEVINTERFACE_PARCLASS
	//{ 0x811FC6A5, 0xF728, 0x11D0, { 0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1 } }
};
 

// 更新设备状态
void UpdateDevice(PDEV_BROADCAST_DEVICEINTERFACE pDevInf, WPARAM wParam)
{
	CString szDevId = pDevInf->dbcc_name + 4;
	int idx = szDevId.ReverseFind(_T('#'));
	szDevId.Truncate(idx);
	szDevId.Replace(_T('#'), _T('\\'));
	szDevId.MakeUpper();

	idx = 0;
	while (1)
	{
		CString szClass;
		int idx_last = idx;
		idx = szDevId.Find(_T('\\'), idx_last);
		if (idx <= 0)
		{
			;
			szClass = szDevId.Right(szDevId.GetLength() - idx_last);
			_tprintf(szClass);
			_tprintf("\n");
			break;
		}
		szClass = szDevId.Mid(idx_last, idx - idx_last);

		if (szClass.Left(3) == _T("VID"))
		{
			int index = szClass.Find(_T('&'));
			CString t1 = szClass.Left(index);
			CString VID = t1.Right(4);
			CString t2 = szClass.Right(szClass.GetLength() - index -1);
			CString PID = t2.Right(4);
			int nVID; sscanf_s(VID.GetBuffer(VID.GetLength()), "%X", &nVID);
			int nPID; sscanf_s(PID.GetBuffer(PID.GetLength()), "%X", &nPID);

			_tprintf("VID = %X;", nVID);
			_tprintf("PID = %X\n", nPID);
		}

		idx++;
		_tprintf(szClass); 
		_tprintf("\n");
	}
	_tprintf("\n");
	CString szTmp;
	if (DBT_DEVICEARRIVAL == wParam) \
		szTmp.Format(_T("Adding %s\r\n"), szDevId.GetBuffer());
	else
		szTmp.Format(_T("Removing %s\r\n"), szDevId.GetBuffer());

	_tprintf(szTmp);
}

// 设备状态改变
LRESULT DeviceChange(UINT message, WPARAM wParam, LPARAM lParam)
{
	if (DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam)
	{
		PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;
		PDEV_BROADCAST_DEVICEINTERFACE pDevInf; 
		PDEV_BROADCAST_HANDLE pDevHnd;
		PDEV_BROADCAST_OEM pDevOem;
		PDEV_BROADCAST_PORT pDevPort;
		PDEV_BROADCAST_VOLUME pDevVolume;
		switch (pHdr->dbch_devicetype)
		{
		case DBT_DEVTYP_DEVICEINTERFACE:
			pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
			UpdateDevice(pDevInf, wParam);  // 更新设备状态
			break;

		case DBT_DEVTYP_HANDLE:
			pDevHnd = (PDEV_BROADCAST_HANDLE)pHdr;
			break;

		case DBT_DEVTYP_OEM:
			pDevOem = (PDEV_BROADCAST_OEM)pHdr;
			break;

		case DBT_DEVTYP_PORT:
			pDevPort = (PDEV_BROADCAST_PORT)pHdr;
			break;

		case DBT_DEVTYP_VOLUME:
			pDevVolume = (PDEV_BROADCAST_VOLUME)pHdr;
			break;
		}
	}
	return 0;
}

// 当前线程消息循环
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_PAINT:
		break;
	case WM_SIZE:
		break;
	case WM_DEVICECHANGE:   // 设备状态改变
		return DeviceChange(message, wParam, lParam);
	}

	return DefWindowProc(hWnd, message, wParam, lParam);
}

ATOM MyRegisterClass()
{
	WNDCLASS wc = { 0 };
	wc.lpfnWndProc = WndProc;              // 消息循环接收类注册，WndProc是函数指针
	wc.hInstance = GetModuleHandle(NULL);  // 当前进程句柄
	wc.lpszClassName = CLASS_NAME;         // 名称
	return RegisterClass(&wc);             // 执行注册 
}

// 创建一个空的窗口隐藏的窗口用来接收消息，失败收不到消息
bool CreateMessageOnlyWindow()
{
	/*
	HWND CreateWindowEx(
        DWORD DdwExStyle,        //窗口的扩展风格
        LPCTSTR lpClassName,    //指向注册类名的指针
        LPCTSTR lpWindowName,   //指向窗口名称的指针
        DWORD dwStyle,          //窗口风格
        int x,                  //窗口的水平位置
        int y,                  //窗口的垂直位置
        int nWidth,             //窗口的宽度
        int nHeight,            //窗口的高度
        HWND hWndParent,        //父窗口的句柄
        HMENU hMenu,            //菜单的句柄或是子窗口的标识符
        HINSTANCE hInstance,    //应用程序实例的句柄
        LPVOID lpParam          //指向窗口的创建数据
        );
	*/
	hWnd = CreateWindowEx(0, CLASS_NAME, _T(""), WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,  // x, y, width, height
		NULL,       // Parent window    
		NULL,       // Menu
		GetModuleHandle(NULL),  // Instance handle
		NULL        // Additional application data
	);

	return hWnd != NULL;
}

// 注册设备事件捕获，支持后台监听，否则收不到消息
void RegisterDeviceNotify()
{
	HDEVNOTIFY hDevNotify;
	for (int i = 0; i < sizeof(GUID_DEVINTERFACE_LIST) / sizeof(GUID); i++)
	{
		DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
		ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
		NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
		NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
		NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_LIST[i];
		hDevNotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
	}
}

DWORD WINAPI ThrdFunc(LPVOID lpParam)   // 线程函数
{
	if (0 == MyRegisterClass()) // 注册类
		return -1;


	if (!CreateMessageOnlyWindow()) // 创建默认窗口来接受消息
		return -1;

	RegisterDeviceNotify();   // 注册设备通知

	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (msg.message == THRD_MESSAGE_EXIT)   // 收到线程退出的消息
		{
			cout << "worker receive the exiting Message..." << endl;
			return 0;
		}

		TranslateMessage(&msg); // 转换（处理）消息
		DispatchMessage(&msg);  // 分发消息
	}

	return 0;
}

int main(int argc, char** argv)
{
	DWORD iThread;
	HANDLE hThread = CreateThread(NULL, 0, ThrdFunc, NULL, 0, &iThread);
	if (hThread == NULL) {
		cout << "error" << endl;
		return -1;
	}

	char chQtNum;
	do
	{
		cout << "enter Q/q for quit: " << endl;
		cin >> chQtNum;

	} while (chQtNum != 'Q' && chQtNum != 'q');

	PostThreadMessage(iThread, THRD_MESSAGE_EXIT, 0, 0);  // 发送线程退出消息
	WaitForSingleObject(hThread, INFINITE);
	CloseHandle(hThread);
	return 0;
} 
